import {
  animate,
  state,
  style,
  transition,
  trigger
} from '@angular/animations';
import { CdkOverlayOrigin, ConnectionPositionPair, Overlay, OverlayPositionBuilder } from '@angular/cdk/overlay';
import {
  AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef,
  Component,
  ElementRef,
  EventEmitter,
  Input, OnChanges,
  OnInit,
  Output,
  Renderer2, SimpleChanges,
  TemplateRef,
  ViewChild, ViewEncapsulation,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { slideMotion } from '@shared/apes/core';
import { ApesUpdateHostClassService as UpdateCls } from '../core/services/update-host-class.service';
import { isNotNil } from '../core/util/check';
import { toBoolean } from '../core/util/convert';

@Component({
  selector   : 'apes-time-picker',
  exportAs: 'apesTimePicker',
  templateUrl: './apes-time-picker.component.html',
  animations : [slideMotion],
  providers  : [UpdateCls, { provide: NG_VALUE_ACCESSOR, useExisting: ApesTimePickerComponent, multi: true }],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ApesTimePickerComponent implements ControlValueAccessor, OnInit, AfterViewInit, OnChanges  {
  private _disabled = false;
  private _value: Date | null = null;
  private _allowEmpty = true;
  private _autoFocus = false;
  private _onChange: (value: Date) => void;
  private _onTouched: () => void;
  private _hideDisabledOptions = false;
  prefixCls = 'apes-time-picker';
  isInit = false;
  origin: CdkOverlayOrigin;
  overlayPositions: ConnectionPositionPair[] = [ {
    originX : 'start',
    originY : 'top',
    overlayX: 'end',
    overlayY: 'top',
    offsetX : 0,
    offsetY : 0
  } ];
  @ViewChild('inputElement',{static:true}) inputRef: ElementRef;
  @Input() apesSize: string | null = null;
  @Input() apesHourStep = 1;
  @Input() apesMinuteStep = 1;
  @Input() apesSecondStep = 1;
  @Input() apesClearText = 'clear';
  @Input() apesPopupClassName = '';
  @Input() apesPlaceHolder = '';
  @Input() apesAddOn: TemplateRef<void>;
  @Input() apesDefaultOpenValue = new Date();
  @Input() apesDisabledHours: () => number[];
  @Input() apesDisabledMinutes: (hour: number) => number[];
  @Input() apesDisabledSeconds: (hour: number, minute: number) => number[];
  @Input() apesFormat = 'HH:mm:ss';
  @Input() apesOpen = false;
  @Input() apesUse12Hours = false;
  @Output() readonly apesOpenChange = new EventEmitter<boolean>();

  @Input()
  set apesHideDisabledOptions(value: boolean) {
    this._hideDisabledOptions = toBoolean(value);
  }

  get apesHideDisabledOptions(): boolean {
    return this._hideDisabledOptions;
  }

  @Input()
  set apesAllowEmpty(value: boolean) {
    this._allowEmpty = toBoolean(value);
  }

  get apesAllowEmpty(): boolean {
    return this._allowEmpty;
  }

  @Input()
  set apesAutoFocus(value: boolean) {
    this._autoFocus = toBoolean(value);
    this.updateAutoFocus();
  }

  get apesAutoFocus(): boolean {
    return this._autoFocus;
  }

  @Input()
  set apesDisabled(value: boolean | string) {
    this._disabled = toBoolean(value);
    const input = this.inputRef.nativeElement as HTMLInputElement;
    if (this._disabled) {
      this.renderer.setAttribute(input, 'disabled', '');
    } else {
      this.renderer.removeAttribute(input, 'disabled');
    }
  }

  get apesDisabled(): boolean | string {
    return this._disabled;
  }

  set value(value: Date | null) {
    this._value = value;
    if (this._onChange) {
      this._onChange(this.value);
    }
    if (this._onTouched) {
      this._onTouched();
    }
  }

  get value(): Date | null {
    return this._value;
  }

  open(): void {
    if (this.apesDisabled) {
      return;
    }
    this.apesOpen = true;
    this.apesOpenChange.emit(this.apesOpen);
  }

  close(): void {
    this.apesOpen = false;
    this.apesOpenChange.emit(this.apesOpen);
  }

  updateAutoFocus(): void {
    if (this.isInit && !this.apesDisabled) {
      if (this.apesAutoFocus) {
        this.renderer.setAttribute(this.inputRef.nativeElement, 'autofocus', 'autofocus');
      } else {
        this.renderer.removeAttribute(this.inputRef.nativeElement, 'autofocus');
      }
    }
  }
  onClickClearBtn(): void {
    this.value = null;
  }
  private setClassMap(): void {
    this.updateCls.updateHostClass(this.element.nativeElement, {
      [ `${this.prefixCls}` ]               : true,
      [ `${this.prefixCls}-${this.apesSize}` ]: isNotNil(this.apesSize)
    });
  }

  focus(): void {
    if (this.inputRef.nativeElement) {
      this.inputRef.nativeElement.focus();
    }
  }

  blur(): void {
    if (this.inputRef.nativeElement) {
      this.inputRef.nativeElement.blur();
    }
  }

  constructor(private element: ElementRef,
              private renderer: Renderer2,
              private updateCls: UpdateCls,
              public cdr: ChangeDetectorRef) {
  }

  ngOnInit(): void {
    this.setClassMap();
    this.origin = new CdkOverlayOrigin(this.element);
  }
  ngOnChanges(changes: SimpleChanges): void {
    const { apesUse12Hours, nzFormat } = changes;
    if (apesUse12Hours && !apesUse12Hours.previousValue && apesUse12Hours.currentValue && !nzFormat) {
      this.apesFormat = 'h:mm:ss a';
    }
  }
  ngAfterViewInit(): void {
    this.isInit = true;
    this.updateAutoFocus();
  }

  writeValue(time: Date | null): void {
    this._value = time;
    this.cdr.markForCheck();
  }

  registerOnChange(fn: (time: Date) => void): void {
    this._onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this._onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.apesDisabled = isDisabled;
    this.cdr.markForCheck();
  }
}
